import subprocess
import sys
import os
import time
import re
import traceback
from pydoc import html
from typing import List, Dict
from datetime import datetime

# 配置参数
device_type = "S01"



PYTHON_EXECUTABLE = sys.executable

def find_project_root(start_path: str = None, marker: str = "requirements.txt") -> str:
    """定位项目根目录（兼容3.7）"""
    if not start_path:
        start_path = os.path.dirname(os.path.abspath(__file__))

    current_path = start_path
    for _ in range(5):
        if os.path.exists(os.path.join(current_path, marker)):
            return os.path.realpath(current_path)
        current_path = os.path.dirname(current_path)

    return os.path.realpath(start_path)


def get_test_scripts() -> List[str]:
    """获取测试脚本列表（兼容3.7）"""
    project_root = find_project_root()
    test_dir = os.path.join(project_root, "test_cases", f"test_cases_{device_type}")

    if not os.path.exists(test_dir):
        raise FileNotFoundError(f"测试目录不存在: {test_dir}")

    valid_scripts = []
    for f in sorted(os.listdir(test_dir)):
        if f.startswith("Test_case_") and f.endswith(".py") and not f.startswith('_'):
            full_path = os.path.join(test_dir, f)
            if os.path.isfile(full_path) and os.access(full_path, os.R_OK):
                valid_scripts.append(full_path)

    def sort_key(x: str) -> int:
        digits = re.findall(r'\d+', os.path.basename(x))
        return int(digits[-1]) if digits else 0

    return sorted(valid_scripts, key=sort_key)


def execute_script(script_path: str) -> Dict[str, object]:
    """执行测试脚本（兼容3.7）"""
    project_root = find_project_root()
    env = os.environ.copy()
    env["PYTHONPATH"] = f"{project_root}{os.pathsep}{env.get('PYTHONPATH', '')}"

    result = {
        'script': os.path.basename(script_path),
        'status': 'pending',
        'output': [],
        'duration': 0.0,
        'successes': 0,
        'failures': 0,
        'errors': 0,
        'return_code': -1
    }

    start_time = time.time()

    try:
        completed = subprocess.run(
            [PYTHON_EXECUTABLE, "-u", script_path],
            capture_output=True,
            text=True,
            timeout=600,
            env=env,
            cwd=project_root
        )

        raw_output = completed.stdout + "\n" + completed.stderr
        output_lines = raw_output.strip().splitlines()

        # 改进的测试结果解析
        test_stats = {'successes': 0, 'failures': 0, 'errors': 0}
        total_tests = 0
        result_pattern = re.compile(r"^(OK|FAILED|ERROR)(?:\s+$.*?$)?$")

        for line in output_lines:
            # 解析测试用例总数
            if line.startswith("Ran "):
                total_match = re.search(r"Ran (\d+) tests? in", line)
                if total_match:
                    total_tests = int(total_match.group(1))

            # 精确提取失败/错误数量
            failures_match = re.search(r'failures=(\d+)', line)
            if failures_match:
                test_stats['failures'] += int(failures_match.group(1))

            errors_match = re.search(r'errors=(\d+)', line)
            if errors_match:
                test_stats['errors'] += int(errors_match.group(1))

        # 增强的错误检测
        has_critical_error = any(
            re.search(
                r'\b(ERROR|FAIL|CRITICAL|Exception|Traceback)\b',
                line,
                re.IGNORECASE
            )
            for line in output_lines
        )

        # 系统级错误检测
        return_code = completed.returncode
        system_error = False
        if return_code < 0 or return_code >= 128:
            system_error = True
            signal_num = return_code if return_code < 0 else return_code - 128
            output_lines.append(f"🆘 SYSTEM ERROR: Process terminated by signal {signal_num}")

        # 状态判断逻辑（优先级从高到低）
        status = 'unknown'
        if system_error:
            status = 'error'
        elif has_critical_error:
            status = 'failed'
        elif return_code != 0:
            status = 'error'
        elif test_stats['failures'] > 0:
            status = 'failed'
        elif test_stats['errors'] > 0:
            status = 'error'
        elif return_code == 0:
            status = 'passed'

        # 保底机制
        if return_code == 0 and test_stats['successes'] == 0 and total_tests > 0:
            test_stats['successes'] = total_tests - test_stats['failures'] - test_stats['errors']

        # 更新结果
        result.update({
            'output': output_lines,
            'return_code': return_code,
            'duration': time.time() - start_time,
            'successes': test_stats['successes'],
            'failures': test_stats['failures'],
            'errors': test_stats['errors'],
            'status': status
        })

    except subprocess.TimeoutExpired:
        result.update({
            'status': 'timeout',
            'duration': time.time() - start_time,
            'output': ["⏰ TEST TIMEOUT: Execution exceeded 10 minutes"]
        })
    except Exception as e:
        result.update({
            'status': 'error',
            'output': [f"🚨 EXECUTION ERROR: {str(e)}"]
        })

    return result

def generate_test_report(results: List[Dict]) -> str:
    """生成HTML测试报告（兼容3.7）"""
    project_root = find_project_root()
    report_dir = os.path.join(project_root, "logs", "report")
    os.makedirs(report_dir, exist_ok=True)

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    html_report = os.path.join(report_dir, "test_report_{}.html".format(timestamp))

    # 统计信息
    stats = {
        'total': len(results),
        'passed': sum(1 for r in results if r['status'] == 'passed'),
        'failed': sum(1 for r in results if r['status'] == 'failed'),
        'error': sum(1 for r in results if r['status'] in ('error', 'timeout')),
        'successes': sum(r['successes'] for r in results),
        'failures': sum(r['failures'] for r in results),
        'errors': sum(r['errors'] for r in results),
        'total_time': sum(r['duration'] for r in results)
    }

    # 生成表格行
    rows = []
    for res in results:
        output_content = html.escape('\n'.join(res['output']))
        row = (
            "<tr>"
            "<td>{script}</td>"
            "<td><span class='status {status}'>{status_upper}</span></td>"
            "<td>{successes}</td>"
            "<td>{failures}</td>"
            "<td>{errors}</td>"
            "<td>{duration:.1f}s</td>"
            "<td><pre>{output}</pre></td>"
            "</tr>"
        ).format(
            script=html.escape(res['script']),
            status=res['status'],
            status_upper=res['status'].upper(),
            successes=res['successes'],
            failures=res['failures'],
            errors=res['errors'],
            duration=res['duration'],
            output=output_content
        )
        rows.append(row)

    # 构建HTML内容
    html_content = (
        "<!DOCTYPE html>"
        "<html>"
        "<head>"
        "<title>测试报告 {timestamp}</title>"
        "<style>{styles}</style>"
        "</head>"
        "<body>"
        "<h1>自动化测试报告</h1>"
        "<div class='summary'>{summary}</div>"
        "<h2>详细结果</h2>"
        "<table>{header}{rows}</table>"
        "</body>"
        "</html>"
    ).format(
        timestamp=timestamp,
        styles=STYLES,
        summary=build_summary(stats),
        header=(
            "<tr>"
            "<th>脚本名称</th><th>状态</th><th>成功用例</th>"
            "<th>失败用例</th><th>错误用例</th><th>耗时</th><th>输出日志</th>"
            "</tr>"
        ),
        rows=''.join(rows)
    )

    # 写入文件
    with open(html_report, 'w', encoding='utf-8') as f:
        f.write(html_content)

    return html_report

# 样式表单独定义
STYLES = """
<style>
    /* 保持原有样式不变 */
    body { font-family: Arial, sans-serif; margin: 20px; }
    .summary { 
        background: #f5f5f5; 
        padding: 20px; 
        border-radius: 5px;
        margin-bottom: 20px;
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        gap: 15px;
    }
    /* 其他样式保持不变 */
</style>
"""

def build_summary(stats):
    """构建摘要部分的HTML"""
    return (
        "<div class='summary-item'>"
        "<h3>总脚本数</h3><p>{total}</p></div>"
        "<div class='summary-item'>"
        "<h3>通过数</h3><p class='status passed'>{passed}</p></div>"
        "<div class='summary-item'>"
        "<h3>失败数</h3><p class='status failed'>{failed}</p></div>"
        "<div class='summary-item'>"
        "<h3>错误数</h3><p class='status error'>{error}</p></div>"
        "<div class='summary-item'>"
        "<h3>总用例数</h3><p>{total_cases}</p></div>"
        "<div class='summary-item'>"
        "<h3>总耗时</h3><p>{total_time:.1f}秒</p></div>"
    ).format(
        total=stats['total'],
        passed=stats['passed'],
        failed=stats['failed'],
        error=stats['error'],
        total_cases=stats['successes'] + stats['failures'] + stats['errors'],
        total_time=stats['total_time']
    )
def generate_html_report(results: List[Dict]) -> str:
    """生成美观的HTML测试报告"""
    project_root = find_project_root()
    report_dir = os.path.join(project_root, "logs", "report")
    os.makedirs(report_dir, exist_ok=True)

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    html_report = os.path.join(report_dir, f"test_report_{timestamp}.html")

    # 样式设计
    styles = """
    <style>
        body { font-family: Arial, sans-serif; margin: 2rem; }
        .report-title { color: #2c3e50; text-align: center; }
        .summary-card {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 1.5rem;
            margin: 1rem 0;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 1rem;
            margin-top: 1rem;
        }
        .stat-item {
            text-align: center;
            padding: 1rem;
            border-radius: 8px;
            color: white;
        }
        .passed { background: #2ecc71; }
        .failed { background: #e74c3c; }
        .error { background: #f39c12; }
        .details-table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 1.5rem;
        }
        .details-table th, 
        .details-table td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        .status-badge {
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 0.9em;
        }
        pre {
            background: #f4f4f4;
            padding: 1rem;
            border-radius: 4px;
            overflow-x: auto;
        }
    </style>
    """

    # 统计计算
    stats = {
        'total': len(results),
        'passed': sum(1 for r in results if r['status'] == 'passed'),
        'failed': sum(1 for r in results if r['status'] == 'failed'),
        'error': sum(1 for r in results if r['status'] in ('error', 'timeout')),
        'total_time': sum(r['duration'] for r in results),
        'success_cases': sum(r['successes'] for r in results),
        'failed_cases': sum(r['failures'] for r in results),
        'error_cases': sum(r['errors'] for r in results)
    }

    # 构建HTML内容
    with open(html_report, 'w', encoding='utf-8') as f:
        f.write(f"""
        <!DOCTYPE html>
        <html lang="zh-CN">
        <head>
            <meta charset="UTF-8">
            <title>{device_type} 测试报告</title>
            {styles}
        </head>
        <body>
            <h1 class="report-title">{device_type} 自动化测试报告</h1>
            <div class="summary-card">
                <h2>执行概要</h2>
                <div class="stats-grid">
                    <div class="stat-item passed">
                        <div class="stat-value">{stats['passed']}</div>
                        <div class="stat-label">通过</div>
                    </div>
                    <div class="stat-item failed">
                        <div class="stat-value">{stats['failed']}</div>
                        <div class="stat-label">失败</div>
                    </div>
                    <div class="stat-item error">
                        <div class="stat-value">{stats['error']}</div>
                        <div class="stat-label">异常</div>
                    </div>
                </div>
                <p>总执行时间: {stats['total_time']:.2f}s</p>
                <p>总用例统计: 
                    ✅ {stats['success_cases']} &nbsp;
                    ❌ {stats['failed_cases']} &nbsp;
                    ⚠️ {stats['error_cases']}
                </p>
            </div>

            <h2>详细结果</h2>
            <table class="details-table">
                <thead>
                    <tr>
                        <th>测试脚本</th>
                        <th>状态</th>
                        <th>耗时(s)</th>
                        <th>成功用例</th>
                        <th>失败用例</th>
                        <th>错误用例</th>
                        <th>输出日志</th>
                    </tr>
                </thead>
                <tbody>
        """)

        # 填充表格数据
        newline = '\n'
        for res in results:
            status_class = {
                'passed': 'passed',
                'failed': 'failed',
                'error': 'error',
                'timeout': 'error'
            }.get(res['status'], 'error')

            f.write(f"""
            <tr>
                <td>{html.escape(res['script'])}</td>
                <td>
                    <span class="status-badge {status_class}">
                        {res['status'].upper()}
                    </span>
                </td>
                <td>{res['duration']:.2f}</td>
                <td>{res['successes']}</td>
                <td>{res['failures']}</td>
                <td>{res['errors']}</td>
                <td>
                    <pre>{html.escape(newline.join(res['output']))}</pre>
                </td>
            </tr>
            """)

        f.write("""
                </tbody>
            </table>
            <footer style="margin-top: 2rem; text-align: center; color: #666;">
                报告生成时间: {timestamp}
            </footer>
        </body>
        </html>
        """.format(timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")))

    return html_report

def main():
    """主执行流程（兼容3.7）"""
    try:
        test_scripts = get_test_scripts()

        if not test_scripts:
            print("⚠️ 未发现任何测试脚本")
            return

        print(f"🔍 在 {find_project_root()} 发现 {len(test_scripts)} 个测试脚本")

        results = []
        for idx, script in enumerate(test_scripts, 1):
            script_name = os.path.basename(script)
            print(f"\n▶ 正在执行 ({idx}/{len(test_scripts)}) {script_name}")

            result = execute_script(script)
            results.append(result)

            status_icons = {
                'passed': '✅',
                'failed': '❌',
                'error': '⚠️',
                'timeout': '⏰',
                'unknown': '❓'
            }
            icon = status_icons.get(result['status'], '❓')
            print(f"{icon} 状态: {result['status'].upper()} | 耗时: {result['duration']:.1f}s")

        html_report = generate_html_report(results)
        print(f"\n🌐 HTML报告路径: {os.path.abspath(html_report)}")

        # 自动打开报告（Linux系统）
        if sys.platform.startswith('linux'):
            os.system(f'xdg-open "{html_report}"')

    except Exception as e:
        print(f"\n❌ 严重错误: {str(e)}")
        print("追踪信息:")
        print(traceback.format_exc())

if __name__ == "__main__":
    main()